#include "m1130.h"
#include "misc.h"
#include "m1130_rtc.h"
#include "m1130_utility_rtc.h"
#include <stdio.h>

/********************************************************
 *                                                      *
 *               date functions                         *
 *                                                      *
 ********************************************************/

#define MINUTE 60
#define HOUR (60*MINUTE)
#define DAY (24*HOUR)
#define YEAR (365*DAY)
#define UTC		8

uint8_t timeChanged;
uint8_t alarmChanged;
Date gCurTime;

static const uint32_t MonthLeap[12] =
{
  0,
  DAY*(31),
  DAY*(31+29),
  DAY*(31+29+31),
  DAY*(31+29+31+30),
  DAY*(31+29+31+30+31),
  DAY*(31+29+31+30+31+30),
  DAY*(31+29+31+30+31+30+31),
  DAY*(31+29+31+30+31+30+31+31),
  DAY*(31+29+31+30+31+30+31+31+30),
  DAY*(31+29+31+30+31+30+31+31+30+31),
  DAY*(31+29+31+30+31+30+31+31+30+31+30)
};

static const uint32_t MonthCom[12] =
{
  0,
  DAY*(31),
  DAY*(31+28),
  DAY*(31+28+31),
  DAY*(31+28+31+30),
  DAY*(31+28+31+30+31),
  DAY*(31+28+31+30+31+30),
  DAY*(31+28+31+30+31+30+31),
  DAY*(31+28+31+30+31+30+31+31),
  DAY*(31+28+31+30+31+30+31+31+30),
  DAY*(31+28+31+30+31+30+31+31+30+31),
  DAY*(31+28+31+30+31+30+31+31+30+31+30)
};


static int isLeapYear(uint16_t year)
{
  return (((year%4==0) && (year%100!=0))||(year%400==0));
}

static uint16_t daysInLeapYear(uint16_t cur_year)
{
  uint16_t days = 0;
  while(cur_year > 1970)
  {
    cur_year--;
    if(isLeapYear(cur_year))
      days++;
  }
return days;
}

void getDateByTimeStamp(Date *date, uint32_t seconds)
{
  int i;
  uint32_t *Month;
  uint32_t min_total;
  uint32_t hour_total;
  uint32_t day_total;
  uint16_t year;
  uint16_t mon;
  int lday; /*day of a year*/
  int llday;

  seconds    = seconds + HOUR*UTC;
  min_total  = seconds / 60;
  hour_total = min_total / 60;
  day_total  = hour_total / 24;
  day_total  = day_total + 719527; /* days since March 1, 1 BC */
  year       = (day_total+1) * 400 / (365 * 400 + 100 - 4 + 1);
  lday       = day_total - (365 * year + year	/ 4 -	year / 100 + year / 400) + 1;

  if(isLeapYear(year))
  {
    Month = (uint32_t *)MonthLeap;
    lday += 1;
  }
  else
    Month = (uint32_t *)MonthCom;

  for(i=1; i<12; i++)
  {
    if(lday <= Month[i]/DAY)
    {
      break;
    }
  }
  mon = i;

  llday = lday - Month[mon-1]/DAY;

  date->sec   = seconds % 60;
  date->min   = min_total % 60;
  date->hour  = hour_total % 24;
  date->month = mon;
  date->day   = llday;
  date->year  = year;
  date->wday  = (day_total - 1) % 7 + 1;
}

uint32_t getTimeStampByDate(Date *date)
{
  uint32_t *Month;
  uint32_t llseconds;
  uint16_t year;
  uint8_t mon;
  uint8_t mday;
  uint16_t hour;
  uint8_t min;
  uint8_t sec;
  uint16_t years;
  uint16_t leapMonthDays;

  year = date->year;
  mon = date->month;
  mday = date->day;
  hour = date->hour;
  min = date->min;
  sec = date->sec;
  years = year-1970;

  if(isLeapYear(year))
    Month = (uint32_t *)MonthLeap;
  else
    Month = (uint32_t *)MonthCom;

  leapMonthDays = daysInLeapYear(year);
  llseconds = YEAR*years + DAY*leapMonthDays;

  llseconds += Month[mon-1];
  llseconds += DAY*(mday-1);
  llseconds += HOUR*hour;
  llseconds += MINUTE*min;
  llseconds += sec;
  llseconds -= HOUR*UTC;

  return llseconds;
}

/*****************date functions end*********************/


/**
  * @brief get date
  *
  */
void GetDate(Date *date)
{
  uint32_t sec;
  sec  = RTC_GetCounter();
  getDateByTimeStamp(date, sec);
}

/**
  * @brief set date
  *
  */
void SetDate(Date *date)
{
  uint32_t sec = getTimeStampByDate(date);
  RTC_SetCounter(sec);
}

/**
  * @brief get alarm
  *
  */
void GetAlarm(Date *date)
{
  uint32_t sec;
  sec = RTC_GetAlarm();
  getDateByTimeStamp(date, sec);
}


/**
  * @brief set alarm
  *
  */
void SetAlarm(Date *date)
{
  uint32_t sec;
  sec = getTimeStampByDate(date);
  RTC_SetAlarm(sec);
}

Date mydate = {2018,1,1,0,0,0,0};	//can be set by CMD
/**
  * @brief rtc configuration example
  *
  */
void RTC_Configuration(void)
{
  NVIC_InitTypeDef NVIC_InitStruct;

  timeChanged = 0;
  alarmChanged = 0;
  
  RCC->PDRUNCFG &= ~(1 << 7);

  RTC_CLKSET(ENABLE);

  RTC_ClockSelect(RTC_CLKSOURCE_LSE);
  RTC_ClearFlag(RTC_FLAG_ALARM | RTC_FLAG_SEC);

  NVIC_InitStruct.NVIC_IRQChannel = RTC_IRQn;
  NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
  NVIC_InitStruct.NVIC_IRQChannelPriority = 0;
  NVIC_Init(&NVIC_InitStruct);

  //RTC_ITConfig(RTC_IT_ALARM | RTC_IT_SEC, ENABLE);
  RTC_ITConfig(RTC_IT_SEC, ENABLE);	//RTC_IT_ALARM should be opened by CMD

  if(RTC->CTRL & RTC_CTRL_EN)
  {
    return;
  }
  
  SetDate(&mydate);

  RTC_Cmd(ENABLE);
}

/**
  * @brief rtc interrupt example
  *
  */
void RTC_IRQHandler(void)
{
  if(RTC_GetFlagStatus(RTC_FLAG_SEC))
  {
    GetDate(&gCurTime);
    //printf("%04d.%02d.%02d-%02d:%02d:%02d xinqi %d\r\n", tmp.year, tmp.month, tmp.day, tmp.hour, tmp.min, tmp.sec, tmp.wday);
    timeChanged = 1;
    RTC_ClearITPendingBit(RTC_IT_SEC);
  }
  if(RTC_GetFlagStatus(RTC_FLAG_ALARM))
  {
    printf("alarm\r\n");
    alarmChanged = 1;
    RTC_ClearITPendingBit(RTC_IT_ALARM);
  }
}

